package websocket

import (
	"gitee.com/sdynasty/clever/peer"
	"errors"
	"github.com/gorilla/websocket"
	"sync"
	"time"
)

const (
	writeWait          = 20 * time.Second
	recvWait           = 60 * time.Second
	pingPeriod         = (recvWait * 9) / 10
	maxFrameMessageLen = 16 * 1024 //4 * 4096
	maxSendBuffer      = 16
)


type wsConnection struct {
	peer.ConnectionIdentify
	mgr     *peer.SessionManager
	conn    *websocket.Conn
	send    chan []byte
	running bool
	mutex sync.Mutex  // 对closeChan关闭上锁
}


func newConnection(conn *websocket.Conn, manager *peer.SessionManager) *wsConnection {
	ws := &wsConnection{
		conn: conn,
		mgr:    manager,
		send: make(chan []byte, maxSendBuffer),
	}
	go ws.recvLoop()
	go ws.sendLoop()
	ws.running = true
	return ws
}

// 取原始连接
func (ws *wsConnection) Raw() interface{} {
	if ws.conn == nil {
		return nil
	}
	return ws.conn
}

func (ws *wsConnection) RemoteAddr() string {
	if ws.conn == nil {
		return ""
	}
	return ws.conn.RemoteAddr().String()
}

func (ws *wsConnection) Close() {
	if ws.running {
		// 线程安全，可多次调用
		ws.conn.Close()
		ws.running = false
		if ws.mgr != nil {
			ws.mgr.Delete(ws.ID())
		}
	}
}

func (ws *wsConnection) Send(msg []byte) (err error) {
	if !ws.running {
		return errors.New("连接未运行")
	}
	ws.send <- msg
	return
}


// 接收循环
func (ws *wsConnection) recvLoop() {
	defer func() {
		ws.Close()
	}()
	ws.conn.SetReadDeadline(time.Now().Add(recvWait))
	ws.conn.SetPongHandler(func(string) error { ws.conn.SetReadDeadline(time.Now().Add(recvWait)); return nil })
	for ws.running && ws.conn != nil {
		_, data, err := ws.conn.ReadMessage()
		if err != nil {
			break
		}
		// websocket没有粘包问题
		// 考虑单连接同步模式，直接执行
		ws.mgr.ProcessMessage(ws.ID(), data)
	}
}

// 发送循环
func (ws *wsConnection) sendLoop() {
	defer func() {
		ws.Close()
	}()

	for {
		select {
		case msg := <-ws.send:
			ws.conn.SetWriteDeadline(time.Now().Add(writeWait))
			if err := ws.conn.WriteMessage(websocket.BinaryMessage, msg); err != nil {
				return
			}
		}
	}
}